package indi.zhifa.core.auth.filter;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.support.config.FastJsonConfig;
import indi.zhifa.core.auth.interfaces.IAuthObject;
import indi.zhifa.core.auth.interfaces.ITokenObjectParser;
import indi.zhifa.core.auth.properties.AuthProperties;
import indi.zhifa.core.auth.properties.JWTConfig;
import indi.zhifa.core.auth.util.ITokenUtil;
import indi.zhifa.core.common.web.entity.ann.UnLogin;
import indi.zhifa.core.common.web.entity.response.RestResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import java.io.IOException;


@Component
public class LoginFilter implements HandlerInterceptor {

    final String JWT_DECODE;
    final String AUTH_DATA;
    final String CLIENT_JWT_KEY;

    private final AuthProperties mAuthProperties;
    private final JWTConfig mJWTConfig;
    private final ITokenUtil mTokenUtil;
    private final ITokenObjectParser mTokenObjectParser;
    private final FastJsonConfig mFastJsonConfig;

    public LoginFilter(AuthProperties pAuthProperties,
                       ITokenUtil pTokenUtil,
                       ITokenObjectParser pTokenObjectParser,
                       FastJsonConfig pFastJsonConfig) {
        mAuthProperties = pAuthProperties;
        mJWTConfig = mAuthProperties.getJwt();
        JWT_DECODE = mJWTConfig.getJwtDecodeKey();
        AUTH_DATA = mJWTConfig.getAuthDataKey();
        CLIENT_JWT_KEY = mJWTConfig.getClientTokenKey();
        mTokenUtil = pTokenUtil;
        mTokenObjectParser = pTokenObjectParser;
        mFastJsonConfig =  pFastJsonConfig;
    }


    /**
     * 本拦截器功能，如果有jwt_decode字段或该字段为true，则解析auth_data，
     *
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        try {
            return _preHandle(request, response, handler);
        }catch (Exception e) {
            e.printStackTrace();
            RestResponse restResponse = RestResponse.error("解析jwt时发生错误，错误原因为"+e.getMessage());
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json; charset=utf-8");
            response.getWriter().print(JSON.toJSONString(restResponse,mFastJsonConfig.getWriterFeatures()));
        }
        return false;
    }

    private boolean _preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
        UnLogin unLoginAnn = ((HandlerMethod)handler).getMethodAnnotation(UnLogin.class);
        if(null != unLoginAnn) {
            return true;
        }


        String strJwtDecode = request.getHeader(JWT_DECODE);
        if(StringUtils.hasText(strJwtDecode) && "true".equals(strJwtDecode)) {
            String authData = request.getParameter(AUTH_DATA);
            IAuthObject authObject = mTokenObjectParser.parseFromDecodedBase64(authData);
            mTokenUtil.setTokenObject(authObject);
            return true;
        }
        String strRawJwt = request.getHeader(CLIENT_JWT_KEY);
        if(StringUtils.hasText(strRawJwt)){
            IAuthObject authObject = mTokenUtil.decrypt(strRawJwt);
            mTokenUtil.setTokenObject(authObject);
            return true;
        }

        if(null == unLoginAnn){

            RestResponse restResponse = RestResponse.error("消息头没有携带鉴权信息"+CLIENT_JWT_KEY);
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json; charset=utf-8");
            response.getWriter().print(JSON.toJSONString(restResponse,mFastJsonConfig.getWriterFeatures()));
            return false;
        }
        return true;
    }


    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                    @Nullable ModelAndView modelAndView) throws Exception {
        mTokenUtil.clearTokenObject();
    }

}
